#include "console_cli_proc.h"
#include "esp_console.h"
#include "argtable3/argtable3.h"
#include "systeminit.h"
#include "driver/gpio.h"
#include "esp_log.h"
#include <stdio.h>
#include <string.h>
#define TAG     "cli_proc"

static struct {
    struct arg_int *pin;
    struct arg_int *mode;
    struct arg_int *on_time;
    struct arg_int *off_time;
    struct arg_end *end;
} led_ctrl_regs;


static int led_ctrl(int argc, char **argv)
{
    int nerrors = arg_parse(argc, argv, (void **) &led_ctrl_regs);

    if (nerrors) {
        arg_print_errors(stderr, led_ctrl_regs.end, argv[0]);
        return 1;
    }
    int led_pin = 0, led_mode = 0, led_on_time = 0, led_off_time = 0;
    if (led_ctrl_regs.pin->count) {
        led_pin = led_ctrl_regs.pin->ival[0];
        if (led_pin < 0 && led_pin >= GPIO_NUM_MAX) {
            ESP_LOGE(TAG, "led_pin [%d] not support", led_pin);
            return 1;
        }
    }

    if (led_ctrl_regs.mode->count) {
        led_mode = led_ctrl_regs.mode->ival[0];
        if (led_mode > LED_MODE_HEARTBEATE) {
            ESP_LOGE(TAG, "led_mode [%d] not support", led_mode);
            return 1;
        }
    }

    if (led_ctrl_regs.on_time->count) {
        led_on_time = led_ctrl_regs.on_time->ival[0];
    }

    if (led_ctrl_regs.off_time->count) {
        led_off_time = led_ctrl_regs.off_time->ival[0];
    }


    ESP_LOGI(TAG, "led_ctrl pin [%d] mode [%d] off_time [%d] on_time [%d] execute", led_pin, led_mode, led_on_time, led_off_time);

    return led_device_get().upadte_pin(led_pin, led_mode, led_on_time, led_off_time);
}


static void register_led_ctrl(void)
{
    led_ctrl_regs.pin = arg_int0(NULL, NULL, "<gpio pin>", "gpio pin num for led io");
    led_ctrl_regs.mode = arg_int0(NULL, NULL, "<led mode>", "OFF 0, ON 1, FLICKER 2, HARTBEATE 3");
    led_ctrl_regs.on_time = arg_int0(NULL, NULL, "led lights up time>", "0 - 1000");
    led_ctrl_regs.off_time = arg_int0(NULL, NULL, "<led extinguish time>", "0 - 1000");
    led_ctrl_regs.end = arg_end(4);
    
    const esp_console_cmd_t led_ctrl_cmd = {
        .command = "led_ctrl",
        .help = "control led status",
        .hint = NULL,
        .func = &led_ctrl,
        .argtable = &led_ctrl_regs
    };
    ESP_ERROR_CHECK(esp_console_cmd_register(&led_ctrl_cmd));

    
}

static int mt6701_read_proc(int argc, char **argv)
{
    Encoder_MT6701::mt6701_raw_data_t raw_data;
    int ret = encoder_device_get().raw_code_read(&raw_data);

    ESP_LOGI(TAG, "raw_code_read ret    = [%d]", ret);
    ESP_LOGI(TAG, "raw_data.angle_data  = [%d]", raw_data.angle_data);
    ESP_LOGI(TAG, "raw_data.status      = [%d]", raw_data.status);
    ESP_LOGI(TAG, "raw_data.crc         = [%d]", raw_data.crc);
    return ret;
}

void register_mt6701_read(void)
{
    const esp_console_cmd_t mt6701_read_cmd = {
        .command = "mt6701_read",
        .help = "read mt6701 raw code value",
        .hint = NULL,
        .func = &mt6701_read_proc,
        .argtable = NULL
    };
    ESP_ERROR_CHECK(esp_console_cmd_register(&mt6701_read_cmd));
}

static int board_meas_info_get(int argc, char **argv)
{
    ESP_LOGI(TAG, "board temp [%.2f]", meas_device_get().get_board_temp());
    ESP_LOGI(TAG, "board vbus [%.3f]", meas_device_get().get_vbus_volt());
    return 0;
}

static void register_board_meas_info(void)
{
    const esp_console_cmd_t board_meas_info_get_cmd = {
        .command = "board_meas_info_get",
        .help = "get board meas info",
        .hint = NULL,
        .func = &board_meas_info_get,
        .argtable = NULL
    };

    ESP_ERROR_CHECK(esp_console_cmd_register(&board_meas_info_get_cmd));
}

static struct {
    struct arg_int *ch;
    struct arg_int *type;   // 0 in1+in2+ref, 1 in1+in2, 2 ref
    struct arg_int *in_1;
    struct arg_int *in_2;
    struct arg_int *ref;
    struct arg_end *end;
} motor_driver_set_regs;

static int motor_driver_set(int argc, char **argv)
{
    int nerrors = arg_parse(argc, argv, (void **) &motor_driver_set_regs);

    if (nerrors) {
        arg_print_errors(stderr, motor_driver_set_regs.end, argv[0]);
        return 1;
    }
    int ch = motor_driver_set_regs.ch->ival[0];
    int type = motor_driver_set_regs.type->ival[0];
    int in1 = motor_driver_set_regs.in_1->ival[0];
    int in2 = motor_driver_set_regs.in_2->ival[0];
    uint8_t ref = (uint8_t)motor_driver_set_regs.ref->ival[0];

    switch (type)
    {
    case 0:
        motor_driver_get(ch).set(in1, in2, ref);
        break;
    case 1:
        motor_driver_get(ch).set(in1, in2);
        break;
    case 2:
        motor_driver_get(ch).set(ref);
        break;
    default:
        ESP_LOGE(TAG, "type [%d] not support", type);
        return -1;
    }
    ESP_LOGI(TAG, "motor_driver_set ch [%d] type [%d] in1 [%d] in2 [%d] ref [%d]", ch, type, in1, in2, ref);
    return 0;
}

static void register_motor_driver_set(void)
{
    motor_driver_set_regs.ch = arg_int0(NULL, NULL, "<int>", "motor driver ch, 0 = ch a, 1 = ch b");
    motor_driver_set_regs.type = arg_int0(NULL, NULL, "<int>", "set params type, 0 = in1+in2+ref, 1 = in1+in2, 2 = ref");
    motor_driver_set_regs.in_1 = arg_int0(NULL, NULL, "<int>", "motor driver in1 pin value, 0 = low, 1 = high");
    motor_driver_set_regs.in_2 = arg_int0(NULL, NULL, "<int>", "motor driver in2 pin value, 0 = low, 1 = high");
    motor_driver_set_regs.ref = arg_int0(NULL, NULL, "<int>", "motor driver ref value, 0 - 255");
    motor_driver_set_regs.end = arg_end(5);
    const esp_console_cmd_t cmd = {
        .command = "motor_driver_set",
        .help = "get board meas info",
        .hint = NULL,
        .func = &motor_driver_set,
        .argtable = &motor_driver_set_regs
    };

    ESP_ERROR_CHECK(esp_console_cmd_register(&cmd));
}


void register_device_control(void)
{
    register_led_ctrl();
    register_board_meas_info();
    register_mt6701_read();
    register_motor_driver_set();
}
